﻿
#region Using Directives.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using BrightIdeasSoftware;
using GDFlacTool.Common;
using GDFlacTool.Properties;

#endregion

namespace GDFlacTool.Forms
{
    public partial class FormSingleTagEditor : Form
    {
        #region Fields.

        private readonly ObjectListView _objectListView;
        private readonly IList<Track> _tracks;
        private Track _currentTrack;
        private int _index;
        private Image _image;
        private long _imageSize;
        private byte[] _imageByteArray;
        private string _currentFolder;
        public static Control TheActiveControl;
        public static Control ThePreviousControl;

        private event EventHandler EnterEventHandler = delegate { };

        #endregion

        #region Constructors.

        public FormSingleTagEditor(IList<Track> tracks, int index, ObjectListView listView)
        {
            InitializeComponent();

            _objectListView = listView;
            _tracks = tracks;
            _index = index;
            picCoverArt.AllowDrop = true;

            tabMain.SelectedIndex = SingleTagEditorSettings.Default.SelectedTab;
        }

        #endregion

        #region Properties.

        public Image Image
        {
            get { return _image; }
        }

        public long ImageSize
        {
            get { return _imageSize; }
        }

        public byte[] ImageByteArray
        {
            get { return _imageByteArray; }
        }

        #endregion

        #region Form Events.

        private void Control_Enter(object sender, EventArgs e)
        {
            ThePreviousControl = TheActiveControl;
            TheActiveControl = sender as Control;
        }


        private void FormSingleTagEditor_Load(object sender, EventArgs e)
        {
            EnterEventHandler += (Control_Enter);

            Controls.SetEnterEvent(EnterEventHandler);

            Init();
        }

        private void FormSingleTagEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            SingleTagEditorSettings.Default.SelectedTab = tabMain.SelectedIndex;

            SingleTagEditorSettings.Default.Save();
        }

        #endregion

        #region Button Events.

        private void btnSaveAndPrev_Click(object sender, EventArgs e)
        {
            SaveTrack();

            _objectListView.RefreshObject(_currentTrack);

            if (_index - 1 >= 0)
            {
                _currentTrack = _tracks[--_index];

                _objectListView.SelectedIndex = _index;

                ReadInfo();

                ThePreviousControl.Focus();
            }
            else
            {
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void btnSaveAndNext_Click(object sender, EventArgs e)
        {
            SaveTrack();

            _objectListView.RefreshObject(_currentTrack);

            if (_index + 1 < _tracks.Count)
            {
                _currentTrack = _tracks[++_index];

                _objectListView.SelectedIndex = _index;

                ReadInfo();

                ThePreviousControl.Focus();
            }
            else
            {
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveTrack();

            _objectListView.RefreshObject(_currentTrack);

            Close();
        }

        private void btnRemoveTag_Click(object sender, EventArgs e)
        {
            string message = string.Format("Remove all tags from audio file: \n\n{0}?", _currentTrack.FileName);

            DialogResult result = MessageBox.Show(this, message, "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

            if (result == DialogResult.Yes)
            {
                _currentTrack.ClearTags();

                ReadInfo();
            }
        }

        private void btnAddArt_Click(object sender, EventArgs e)
        {
            openFileDialog.Title = "Add Flac Cover Art";
            openFileDialog.Filter = "JPG JPEG(*.jpeg,*.jpg,*.jif,*.jpe)|*.jpeg;*.jpg;*.jif;*.jpe";
            openFileDialog.FilterIndex = 1;
            openFileDialog.InitialDirectory = _currentFolder;

            DialogResult open = openFileDialog.ShowDialog(this);

            if (open == DialogResult.OK)
            {
                if (AddArt(openFileDialog.FileName))
                {
                    btnSaveArt.Enabled = true;
                    btnRemoveArt.Enabled = true;
                    _currentTrack.IsCoverArtChanged = true;
                }
                else
                {
                    _currentTrack.IsCoverArtChanged = false;
                    btnSaveArt.Enabled = false;
                    btnRemoveArt.Enabled = false;
                }
            }
        }

        private void btnSaveArt_Click(object sender, EventArgs e)
        {
            saveFileDialog.Title = @"Save Cover Art Image";
            saveFileDialog.Filter = "JPG(*.JPG)|*.JPG";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.DefaultExt = "JPG";
            saveFileDialog.FileName = "Folder";
            saveFileDialog.InitialDirectory = _currentFolder;

            DialogResult dlgResult = saveFileDialog.ShowDialog(this);

            if (dlgResult == DialogResult.OK)
            {
                SaveArt(saveFileDialog.FileName);
            }
        }

        private void btnRemoveArt_Click(object sender, EventArgs e)
        {
            RemoveArt();
        }

        private void btnLoadFromTextFile_Click(object sender, EventArgs e)
        {
            openFileDialog.Title = "Open Lyric File";
            openFileDialog.Filter = "Lyric File(*.txt)|*.txt";
            openFileDialog.FilterIndex = 1;
            openFileDialog.InitialDirectory = _currentFolder;

            DialogResult open = openFileDialog.ShowDialog(this);

            if (open == DialogResult.OK)
            {
                TextReader tr = null;

                try
                {
                    var sb = new StringBuilder();
                    tr = new StreamReader(openFileDialog.FileName);
                    string line;

                    while ((line = tr.ReadLine()) != null)
                    {
                        sb.AppendLine(line);
                    }

                    txtLyrics.Text = sb.ToString();
                }
                catch (Exception ex)
                {
                    string message = String.Format("There was a problem opening the lyrics file [{0}]\n\n{1}", openFileDialog.FileName, ex.Message);

                    MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    if (tr != null) tr.Close();
                }
            }
        }

        private void btnSaveLyrics_Click(object sender, EventArgs e)
        {
            saveFileDialog.Title = @"Save Lyrics To Text File";
            saveFileDialog.Filter = "Lyrics File(*.txt)|*.txt";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.DefaultExt = "txt";
            saveFileDialog.FileName = "Lyrics";
            saveFileDialog.InitialDirectory = _currentFolder;

            DialogResult dlgResult = saveFileDialog.ShowDialog(this);

            if (dlgResult == DialogResult.OK)
            {
                StreamWriter streamWriter = null;

                try
                {
                    var fileInfo = new FileInfo(saveFileDialog.FileName);
                    streamWriter = fileInfo.CreateText();

                    foreach (string line in txtLyrics.Lines)
                    {
                        streamWriter.WriteLine(line);
                    }
                }
                catch (Exception ex)
                {
                    string message = String.Format("There was a problem saving the lyrics file [{0}]\n\n{1}", saveFileDialog.FileName, ex.Message);

                    MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    if (streamWriter != null) streamWriter.Close();
                }
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtLyrics.Clear();
        }

        private void btnRemoveLeftSpaces_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            foreach (string line in txtLyrics.Lines)
            {
                sb.AppendLine(line.TrimStart());
            }

            txtLyrics.Text = sb.ToString();
        }

        private void btnAudioFileUrl_Click(object sender, EventArgs e)
        {
            Functions.OpenUrl(txtAudioFileUrl.Text);
        }

        private void btnAuthorUrl_Click(object sender, EventArgs e)
        {
            Functions.OpenUrl(txtAuthorUrl.Text);
        }

        private void btnAudioSourceUrl_Click(object sender, EventArgs e)
        {
            Functions.OpenUrl(txtAudioSourceUrl.Text);
        }

        private void btnRadioStationUrl_Click(object sender, EventArgs e)
        {
            Functions.OpenUrl(txtRadioStationUrl.Text);
        }

        private void btnBuyCdUrl_Click(object sender, EventArgs e)
        {
            Functions.OpenUrl(txtBuyCdUrl.Text);
        }

        #endregion

        #region Private Methods.

        private void Init()
        {
            _currentTrack = _tracks[_index];

            _currentFolder = _currentTrack.FilePath;

            _objectListView.SelectedIndex = _index;

            LoadGenreCombo();

            LoadRatingCombo();

            LoadReleaseTypeCombo();

            ReadInfo();
        }

        private void LoadGenreCombo()
        {
            string[] genres = Genres.Audio;

            for (int i = 0; i < Genres.Audio.Length; i++)
            {
                cboGenre.Items.Add(genres[i]);
            }
        }

        private void LoadRatingCombo()
        {
            cboRating.DataSource = typeof(Rating).ToList();
            cboRating.DisplayMember = "Value";
            cboRating.ValueMember = "Key";
        }

        private void LoadReleaseTypeCombo()
        {
            cboReleaseType.Add(ReleaseTypeResource.Blank, "Empty");
            cboReleaseType.Add(ReleaseTypeResource.Album, "Album");
            cboReleaseType.Add(ReleaseTypeResource.Anthology, "Anthology");
            cboReleaseType.Add(ReleaseTypeResource.AudioBook, "Audio book");
            cboReleaseType.Add(ReleaseTypeResource.Bootleg, "Bootleg");
            cboReleaseType.Add(ReleaseTypeResource.Compilation, "Compilation");
            cboReleaseType.Add(ReleaseTypeResource.Digital, "Digital");
            cboReleaseType.Add(ReleaseTypeResource.DVD, "DVD");
            cboReleaseType.Add(ReleaseTypeResource.EP, "EP");
            cboReleaseType.Add(ReleaseTypeResource.Live_Performance, "Live performance");
            cboReleaseType.Add(ReleaseTypeResource.Sampler, "Sampler");
            cboReleaseType.Add(ReleaseTypeResource.MaxiSingle, "Single/Maxi");
            cboReleaseType.Add(ReleaseTypeResource.Sound_Effects, "Sound effects");
            cboReleaseType.Add(ReleaseTypeResource.Soundtrack, "Soundtrack");
            cboReleaseType.Add(ReleaseTypeResource.Video, "Video");

            cboReleaseType.SelectedIndex = 0;
        }

        private bool AddArt(string path)
        {
            if (File.Exists(path))
            {
                FileStream fs = null;
                var ms = new MemoryStream();
                try
                {
                    fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);

                    fs.CopyTo(ms);

                    _imageByteArray = ms.ToArray();

                    _imageSize = _imageByteArray.Length;

                    Image image = Image.FromStream(fs);

                    _image = image;

                    lblFolderCoverArtInfo.Text = String.Format("Picture: {0} x {1}, {2}", image.Width, image.Height, Functions.GetFolderArtSizeFromFile(path));

                    picCoverArt.Image = image;

                    lblDragDrop.Visible = false;

                    return true;
                }
                catch (Exception ex)
                {
                    string message = String.Format("There was a problem opening the cover art picture file [{0}]\n\n{1}", path, ex.Message);

                    MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    if (fs != null) fs.Close();
                    ms.Close();
                }
            }

            picCoverArt.Image = null;
            lblFolderCoverArtInfo.Text = "Picture:";
            return false;
        }

        private void SaveArt(string path)
        {
            byte[] bytes = ImageByteArray;

            MemoryStream ms = null;
            FileStream fs = null;

            try
            {
                ms = new MemoryStream(bytes);

                fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);

                ms.CopyTo(fs);

                fs.Flush();
            }
            catch (Exception ex)
            {
                string message = String.Format("There was a problem saving cover art to file [{0}]\n\n{1}", path, ex.Message);

                MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (fs != null) fs.Close();
                if (ms != null) ms.Close();
            }
        }

        private void RemoveArt()
        {
            picCoverArt.Image = null;
            _imageByteArray = null;
            _image = null;
            _imageSize = 0;
            lblFolderCoverArtInfo.Text = "Picture:";
            btnSaveArt.Enabled = false;
            btnRemoveArt.Enabled = false;
            lblDragDrop.Visible = true;
            _currentTrack.IsCoverArtChanged = true;
        }

        #endregion

        #region Read Tag Info.

        private void ReadInfo()
        {
            Text = string.Format("Tag Editor [{0}]", Functions.ShortenName(_currentTrack.FullPath, 130));

            _image = _currentTrack.ArtImage;
            _imageSize = _currentTrack.ArtSize;

            lblDurationValue.Text = string.Format("{0}", _currentTrack.Time);
            lblBitrateValue.Text = string.Format("{0} kbps", _currentTrack.BitRate);

            if (_currentTrack.Channels == 2)
            {
                lblChannelsValue.Text = "Stereo";
            }
            else
            {
                lblChannelsValue.Text = "Mono";
            }

            lblSampleRateValue.Text = string.Format("{0} Hz", _currentTrack.SampleRate);
            lblEncoderValue.Text = _currentTrack.Encoder;

            txtFile.Text = Functions.ShortenName(_currentTrack.FullPath, 130);
            txtTitle.Text = _currentTrack.Title;
            txtArtist.Text = _currentTrack.Artist;
            txtAlbum.Text = _currentTrack.Album;
            txtAlbumArtist.Text = _currentTrack.Albumartist;
            txtYear.Text = _currentTrack.Year;

            if (cboGenre.Items.Contains(_currentTrack.Genre))
            {
                int index = cboGenre.Items.IndexOf(_currentTrack.Genre);

                cboGenre.SelectedIndex = index;
            }
            else
            {
                cboGenre.Text = _currentTrack.Genre;
            }

            int indexReleaseType = cboReleaseType.Items.IndexOf(Functions.ConvertReleaseTypeToString(_currentTrack.ReleaseType));

            if (indexReleaseType > 0)
            {
                cboReleaseType.SelectedItem = Functions.ConvertReleaseTypeToString(_currentTrack.ReleaseType);
            }
            else
            {
                cboReleaseType.SelectedIndex = 0;
            }

            txtIsrc.Text = _currentTrack.Isrc;
            txtComment.Text = _currentTrack.Comment;

            txtComposer.Text = _currentTrack.Composer;
            txtOriginalArtist.Text = _currentTrack.Originalartist;
            txtCopyright.Text = _currentTrack.Copyright;
            txtUrl.Text = _currentTrack.Url;
            txtEncodedBy.Text = _currentTrack.EncodedBy;
            txtTrack.Text = _currentTrack.TrackNumber;
            txtDisc.Text = _currentTrack.DiscNumber;
            txtCatalog.Text = _currentTrack.Catalog;

            try
            {
                cboRating.SelectedValue = (Rating)Enum.Parse(typeof(Rating), _currentTrack.Rating);
            }
            catch (Exception)
            {
                cboRating.SelectedValue = Rating.Unrated;
            }

            cboMood.SelectedItem = _currentTrack.Mood;

            if (string.IsNullOrEmpty(_currentTrack.Quality))
            {
                cboQuality.Text = string.Empty;
            }
            else
            {
                cboQuality.Text = _currentTrack.Quality.Replace(" copy", "");
            }

            txtBpm.Text = _currentTrack.Bpm;

            chkCompilation.Checked = _currentTrack.Compilation;

            if (_currentTrack.HasFileCoverArt)
            {
                _image = _currentTrack.ArtImage;// _tracks[0].ArtImage;
                _imageByteArray = _currentTrack.ArtByteArray;// _tracks[0].ArtByteArray;
                picCoverArt.Image = _image;
                lblFolderCoverArtInfo.Text = String.Format("Picture: {0} x {1}, {2}", _image.Width, _image.Height, Functions.GetFileArtSizeFromBytes(ImageByteArray.Length));
                btnSaveArt.Enabled = true;
                btnRemoveArt.Enabled = true;
                lblDragDrop.Visible = false;
            }
            else
            {
                _image = null;
                _imageByteArray = null;
                picCoverArt.Image = _image;
                lblFolderCoverArtInfo.Text = "Picture:";
                btnSaveArt.Enabled = false;
                btnRemoveArt.Enabled = false;
                lblDragDrop.Visible = true;
            }

            txtLyrics.Text = _currentTrack.Lyrics;
            txtConductor.Text = _currentTrack.Conductor;
            txtLyricist.Text = _currentTrack.Lyricist;
            txtOriginalLyricist.Text = _currentTrack.OriginalLyricist;
            txtLabel.Text = _currentTrack.Label;
            txtRemixedBy.Text = _currentTrack.RemixedBy;
            txtRadioStationName.Text = _currentTrack.RadioStationName;
            txtAudioFileUrl.Text = _currentTrack.AudioFileUrl;
            txtAuthorUrl.Text = _currentTrack.AuthorUrl;
            txtAudioSourceUrl.Text = _currentTrack.AudioSourceUrl;
            txtRadioStationUrl.Text = _currentTrack.RadioStationUrl;
            txtBuyCdUrl.Text = _currentTrack.BuyCdUrl;
        }

        #endregion

        #region Save Tag Info.

        private void SaveTrack()
        {
            _currentTrack.Title = txtTitle.Text;
            _currentTrack.IsTitleChanged = true;

            _currentTrack.Artist = txtArtist.Text;
            _currentTrack.IsArtistChanged = true;

            _currentTrack.Title = txtTitle.Text;
            _currentTrack.IsTitleChanged = true;

            _currentTrack.Album = txtAlbum.Text;
            _currentTrack.IsAlbumChanged = true;

            _currentTrack.Albumartist = txtAlbumArtist.Text;
            _currentTrack.IsAlbumArtistChanged = true;

            _currentTrack.Year = txtYear.Text;
            _currentTrack.IsYearChanged = true;

            _currentTrack.Genre = cboGenre.Text;
            _currentTrack.IsGenreChanged = true;

            _currentTrack.Isrc = txtIsrc.Text;
            _currentTrack.IsIsrcChanged = true;

            _currentTrack.Comment = txtComment.Text;
            _currentTrack.IsCommentChanged = true;

            _currentTrack.Composer = txtComposer.Text;
            _currentTrack.IsComposerChanged = true;

            _currentTrack.Originalartist = txtOriginalArtist.Text;
            _currentTrack.IsOriginalArtistChanged = true;

            _currentTrack.Copyright = txtCopyright.Text;
            _currentTrack.IsCopyrightChanged = true;

            _currentTrack.Url = txtUrl.Text;
            _currentTrack.IsUrlChanged = true;

            _currentTrack.EncodedBy = txtEncodedBy.Text;
            _currentTrack.IsEncodedByChanged = true;

            _currentTrack.TrackNumber = txtTrack.Text;
            _currentTrack.IsTrackNumberChanged = true;

            _currentTrack.DiscNumber = txtDisc.Text;
            _currentTrack.IsDiscNumberChanged = true;

            _currentTrack.Catalog = txtCatalog.Text;
            _currentTrack.IsCatalogChanged = true;

            if (!string.IsNullOrEmpty(cboRating.ValueMember))
            {
                Rating rating = (Rating)Enum.Parse(typeof(Rating), cboRating.SelectedValue.ToString());

                _currentTrack.Rating = ((int)rating).ToString(CultureInfo.InvariantCulture);
            }
            else
            {
                _currentTrack.Rating = "0";
            }

            _currentTrack.IsRatingChanged = true;

            _currentTrack.Mood = cboMood.Text;
            _currentTrack.IsMoodChanged = true;

            _currentTrack.Quality = string.Format("{0} copy", cboQuality.Text);
            _currentTrack.IsQualityChanged = true;

            _currentTrack.Bpm = txtBpm.Text;
            _currentTrack.IsBpmChanged = true;

            _currentTrack.Compilation = chkCompilation.Checked;

            if (_currentTrack.IsCoverArtChanged)
            {
                if (ImageByteArray != null)
                {
                    _currentTrack.SaveFrontCoverArt(ImageByteArray);
                }
                else
                {
                    _currentTrack.RemoveFrontCoverArt();
                }
            }

            _currentTrack.Lyrics = txtLyrics.Text;
            _currentTrack.IsLyricsChanged = true;

            _currentTrack.Conductor = txtConductor.Text;
            _currentTrack.IsConductorChanged = true;

            _currentTrack.Lyricist = txtLyricist.Text;
            _currentTrack.IsLyricistChanged = true;

            _currentTrack.OriginalLyricist = txtOriginalLyricist.Text;
            _currentTrack.IsOriginalLyricistChanged = true;

            _currentTrack.Label = txtLabel.Text;
            _currentTrack.IsLabelChanged = true;

            _currentTrack.RemixedBy = txtRemixedBy.Text;
            _currentTrack.IsRemixedByChanged = true;

            _currentTrack.RadioStationName = txtRadioStationName.Text;
            _currentTrack.IsRadioStationNameChanged = true;

            _currentTrack.AudioFileUrl = txtAudioFileUrl.Text;
            _currentTrack.IsAudioFileUrlChanged = true;

            _currentTrack.AuthorUrl = txtAuthorUrl.Text;
            _currentTrack.IsAuthorUrlChanged = true;

            _currentTrack.AudioSourceUrl = txtAudioSourceUrl.Text;
            _currentTrack.IsAudioSourceUrlChanged = true;

            _currentTrack.RadioStationUrl = txtRadioStationUrl.Text;
            _currentTrack.IsRadioStationUrlChanged = true;

            _currentTrack.BuyCdUrl = txtBuyCdUrl.Text;
            _currentTrack.IsBuyCdUrlChanged = true;

            if (cboReleaseType.SelectedIndex > 0)
            {
                _currentTrack.ReleaseType = Functions.ConvertReleaseTypeToNumber(cboReleaseType.SelectedText);
            }
            else
            {
                _currentTrack.ReleaseType = "0";
            }

            _currentTrack.IsReleaseTypeChanged = true;

            _currentTrack.SetTags((Id3Actions)MainSettings.Default.Id3Actions);
        }

        #endregion

        #region Drag And Drop.

        private void picCoverArt_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }

            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void picCoverArt_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    string[] filepath = (string[])e.Data.GetData(DataFormats.FileDrop);

                    AddArt(filepath[0]);

                    btnAddArt.Enabled = true;
                    btnRemoveArt.Enabled = true;
                    btnSaveArt.Enabled = true;

                    _currentTrack.IsCoverArtChanged = true;
                }
            }
            catch (Exception ex)
            {
                string message = String.Format("There was a problem adding the cover art picture file!\n\n{0}", ex.Message);

                MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion
    }
}
